﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xrm.Sdk.Workflow;
using System.Activities;
using Microsoft.Xrm.Sdk;
using Microsoft.Crm.Sdk.Messages;
using Microsoft.Crm.Sdk;
using Microsoft.Xrm.Sdk.Query;
using System.Xml.Serialization;
using System.IO;
using System.Runtime.Serialization;
using System.Xml;

/**
 * Copyright 2011 by Alberto Gemin
 * agemin@hotmail.com
 * Version 1.7.0.1
 * 13 Dec 2011
 **/
namespace Gemina.CRM2011.WF.LdgManager
{
    [AgCodeActivity(ActivityNameDeleteSystemView, AgViewsUtils.GroupName)]
    public class AgDeleteSystemView : AgCodeActivityBase
    {

        #region Constants

        private const string ActivityNameDeleteSystemView = "Delete System View";
        private const string Param1InputViewId = "System View Id";
        private const string Param2InputSavedQueryName = "System View Name";
        private const string Param3InputSavedViewReturnedType = "System View Returned Entity";
        private const string Param4InputSavedQueryType = "System View Query Type";
        private const string Param5InputWhenErrorAction = "When Error";
        private const string Param1OutputViewId = "Output View Id";
        private const string Param2OutputResultAction = "Result Action";
        private const string MsgAction = "{0} is not a valid value for {1}. Valid values are \"{2}\" and \"{3}\".";
        private const string MsgBothNull = "{0} and {1} cannot be both null.";
        private const string MsgGuid = "{0} is not a valid Guid for {1}.";
        private const string MsgNotFound = "Could not find a saved query that matches the parameters.";
        private const string MsgMoreFound = "Error: found {0} saved queries that match the parameters.";

        #endregion

        #region Properties

        public string ValidatedEntityLogicalName { get; set; }
        public string ValidatedSavedQueryName { get; set; }
        public int? ValidatedQueryType { get; set; }
        public Guid? ValidatedViewId { get; set; }
        public ActionEnum ValidatedAction { get; set; }

        #endregion

        #region Workflow Input Parameters

        /// <summary>
        /// Input parameter
        /// </summary>
        [Input(Param1InputViewId)]
        public InArgument<String> InputViewId { get; set; }

        /// <summary>
        /// Input parameter
        /// </summary>
        [Input(Param2InputSavedQueryName)]
        public InArgument<String> InputSavedQueryName { get; set; }

        /// <summary>
        /// Input parameter
        /// </summary>
        [Input(Param3InputSavedViewReturnedType)]
        public InArgument<String> InputSavedViewReturnedType { get; set; }

        /// <summary>
        /// Input parameter
        /// </summary>
        [Input(Param4InputSavedQueryType)]
        public InArgument<String> InputSavedQueryType { get; set; }

        /// <summary>
        /// Input parameter
        /// </summary>
        [Input(Param5InputWhenErrorAction)]
        [RequiredArgument]
        public InArgument<String> InputWhenErrorAction { get; set; }

        #endregion

        #region Workflow Output Parameters

        /// <summary>
        /// Output parameter
        /// </summary>
        [Output(Param1OutputViewId)]
        public OutArgument<String> OutputViewId { get; set; }

        /// <summary>
        /// Output parameter
        /// </summary>
        [Output(Param2OutputResultAction)]
        public OutArgument<String> OutputResultAction { get; set; }

        #endregion

        #region CodeActivity

        override protected bool ExecuteBody(CodeActivityContext executionContext)
        {
            this.CheckArguments(executionContext);

            Entity savedQuery = this.FindSavedQuery(executionContext);
            if (savedQuery != null)
            {
                this.DeleteSavedquery(savedQuery, executionContext);
            }

            return true;
        }

        #endregion

        #region Local Methods

        private void CheckArguments(CodeActivityContext executionContext)
        {
            this.ValidatedEntityLogicalName = this.InputSavedViewReturnedType.Get(executionContext);
            this.ValidatedSavedQueryName = this.InputSavedQueryName.Get(executionContext);
            this.ValidatedQueryType = AgViewsUtils.GetQueryType(this.InputSavedQueryType.Get(executionContext), true, Param4InputSavedQueryType, Param2InputSavedQueryName);

            string viewId = this.InputViewId.Get(executionContext);
            if (!string.IsNullOrEmpty(viewId))
            {
                Guid guid;
                if (Guid.TryParse(viewId, out guid))
                {
                    this.ValidatedViewId = guid;
                }
                else
                {
                    throw new AgErrorMessage(string.Format(MsgGuid, viewId, Param1InputViewId));
                }
            }

            string action = this.InputWhenErrorAction.Get(executionContext);
            if (ActionEnum.Ignore.ToString().Equals(action, StringComparison.CurrentCultureIgnoreCase))
            {
                this.ValidatedAction = ActionEnum.Ignore;
            }
            else if (ActionEnum.Error.ToString().Equals(action, StringComparison.CurrentCultureIgnoreCase) || string.IsNullOrEmpty(action))
            {
                this.ValidatedAction = ActionEnum.Error;
            }
            else
            {
                throw new AgErrorMessage(string.Format(MsgAction, action, Param5InputWhenErrorAction,
                   ActionEnum.Ignore.ToString(), ActionEnum.Error.ToString()));
            }

            if (string.IsNullOrEmpty(this.ValidatedSavedQueryName) && null == this.ValidatedViewId)
            {
                throw new AgErrorMessage(string.Format(MsgBothNull, Param1InputViewId, Param2InputSavedQueryName));
            }
        }

        private void DeleteSavedquery(Entity savedQuery, CodeActivityContext executionContext)
        {
            IOrganizationService svc = this.GetService(executionContext);

            svc.Delete(savedQuery.LogicalName, savedQuery.Id);
            this.OutputViewId.Set(executionContext, savedQuery.Id.ToString());
            this.OutputResultAction.Set(executionContext, ActionEnum.Delete.ToString());
        }

        private Entity FindSavedQuery(CodeActivityContext executionContext)
        {
            QueryExpression query = new QueryExpression
            {
                EntityName = AgViewsUtils.EntityNameSavedQuery,
                ColumnSet = new ColumnSet(true),
                Criteria = new FilterExpression()
            };

            if (!string.IsNullOrEmpty(this.ValidatedSavedQueryName))
            {
                query.Criteria.AddCondition(new ConditionExpression
                {
                    AttributeName = AgViewsUtils.FieldName,
                    Operator = ConditionOperator.Equal,
                    Values = { this.ValidatedSavedQueryName }
                });
            }

            if (this.ValidatedQueryType != null)
            {
                query.Criteria.AddCondition(new ConditionExpression
                {
                    AttributeName = AgViewsUtils.FieldQueryType,
                    Operator = ConditionOperator.Equal,
                    Values = { this.ValidatedQueryType.Value }
                });
            }

            if (!string.IsNullOrEmpty(this.ValidatedEntityLogicalName))
            {
                query.Criteria.AddCondition(new ConditionExpression
                {
                    AttributeName = AgViewsUtils.FieldReturnedTypeCode,
                    Operator = ConditionOperator.Equal,
                    Values = { this.ValidatedEntityLogicalName }
                });
            }

            if (this.ValidatedViewId != null)
            {
                query.Criteria.AddCondition(new ConditionExpression
                {
                    AttributeName = AgViewsUtils.FieldSavedQueryId,
                    Operator = ConditionOperator.Equal,
                    Values = { this.ValidatedViewId.Value }
                });
            }

            IOrganizationService svc = this.GetService(executionContext);
            DataCollection<Entity> responses = svc.RetrieveMultiple(query).Entities;

            if (responses.Count == 1)
            {
                return responses[0];
            }
            else if (responses.Count == 0)
            {
                if (this.ValidatedAction == ActionEnum.Error)
                {
                    throw new AgErrorMessage(MsgNotFound);
                }
                else
                {
                    this.OutputResultAction.Set(executionContext, ActionEnum.Ignore.ToString());
                    return null;
                }
            }
            else
            {
                if (this.ValidatedAction == ActionEnum.Error)
                {
                    throw new AgErrorMessage(string.Format(MsgMoreFound, responses.Count));
                }
                else
                {
                    this.OutputResultAction.Set(executionContext, ActionEnum.Ignore.ToString());
                    return null;
                }
            }
        }

        #endregion

    }
}
